// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MapCell.cs" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.Robotics.Navigation.Localization
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.Serialization;

    /// <summary>
    /// Represents an entry in our occupancy map
    /// </summary>
    public struct MapCell
    {
        /// <summary>
        /// The weight associated with the cell. 
        /// </summary>
        public float Weight;

        /// <summary>
        /// The value associated with the map cell.
        /// </summary>
        public float Value;

        /// <summary>
        /// Additional information about the cell, e.g. whether the pixel is in an exclusion zone
        /// </summary>
        public float Metadata;  

        /// <summary>
        /// Initializes a new instance of the MapCell struct.
        /// </summary>
        /// <param name="value">The value associated with the map cell.</param>
        /// <param name="weight">The weight associated with the cell. </param>
        /// <param name="metadata">Additional information about the cell, e.g. whether the pixel is in an exclusion zone</param>
        public MapCell(float value, float weight, float metadata)
        {
            this.Value = value;
            this.Weight = weight;
            this.Metadata = 0;
        }

        /// <summary>
        /// Gets a value indicating whether the cell was ever visited 
        /// </summary>
        public bool WasVisited
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get { return this.Weight > 0; }
        }

        /// <summary>
        /// The equals operator
        /// </summary>
        /// <param name="leftSide">First map cell</param>
        /// <param name="rightSide">Second map cell</param>
        /// <returns>Are the map cell values equal</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator ==(MapCell leftSide, MapCell rightSide)
        {
            // Return true if all the fields match:
            return leftSide.Value == rightSide.Value && leftSide.Weight == rightSide.Weight && leftSide.WasVisited == rightSide.WasVisited;
        }

        /// <summary>
        /// The not equals operator
        /// </summary>
        /// <param name="leftSide">First map cell</param>
        /// <param name="rightSide">Second map cell</param>
        /// <returns>The not equal result</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator !=(MapCell leftSide, MapCell rightSide)
        {
            // Return true if any fields don't match
            return leftSide.Value != rightSide.Value || leftSide.Weight != rightSide.Weight || leftSide.WasVisited != rightSide.WasVisited;
        }

        /// <summary>
        /// Get hash code value.
        /// </summary>
        /// <returns>Hash code.</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override int GetHashCode()
        {
            return this.Value.GetHashCode() ^ this.Weight.GetHashCode() ^ this.WasVisited.GetHashCode();
        }

        /// <summary>
        /// Determine equality with another object.
        /// </summary>
        /// <param name="obj">Another object to which to compare.</param>
        /// <returns>Indication of equality.</returns>
        public override bool Equals(object obj)
        {
            MapCell other = (MapCell)obj;
            return this == other;
        }
    }
}
